home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
emerald
/
emrldsys.lha
/
Language
/
Compiler
/
variables.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-16
|
21KB
|
797 lines
/*
* @(#)variables.c 1.8 6/18/88
*/
#include "assert.h"
#include "genutils.h"
#include "nodes.h"
#include "builtins.h"
#include "regdefs.h"
#include "emit.h"
#include "environment.h"
#include "MyParser.h"
#include "flags.h"
#include "trace.h"
#include "system.h"
#include "semantics.h"
void squirrelStringLiteral(), dumpStringLiterals();
void squirrelVectorLiteral(), dumpVectorLiterals();
/*
* This file defines the variable stack. It is used to keep track of
* partial results in the code-generation process.
*
* When code is being generated for an invocation, the target will be on top
* of the stack, and the parameters will be there in normal order, that is,
* the last parameter will be on top of the stack.
*/
#define MAXVARIABLESTACKDEPTH 100
Variable vStack[MAXVARIABLESTACKDEPTH];
VariablePtr vStackTop = &vStack[-1];
extern NodePtr currentObject;
Boolean vEmpty()
{
return(vStackTop == &vStack[-1]);
}
void vPushDD(data, abcon)
DD data, abcon;
{
assert(vStackTop < &vStack[MAXVARIABLESTACKDEPTH]);
++vStackTop;
vStackTop->data = data;
vStackTop->abCon = abcon;
}
void vPush(v)
Variable v;
{
assert(vStackTop < &vStack[MAXVARIABLESTACKDEPTH]);
*++vStackTop = v;
}
Boolean isPop(d)
DD d;
{
return(d.kind == DD_Address && d.value.address.autoIncrement);
}
Boolean isSameDD(val, var)
DD val, var;
{
return(val.kind == var.kind && val.value.id == var.value.id ||
(val.kind == DD_Address && var.kind == DD_Address &&
val.value.address.base == var.value.address.base &&
val.value.address.hasIndex == var.value.address.hasIndex &&
(!val.value.address.hasIndex ||
val.value.address.indexReg == var.value.address.indexReg) &&
val.value.address.offset == var.value.address.offset &&
!val.value.address.autoIncrement &&
!val.value.address.autoDecrement &&
!var.value.address.autoIncrement &&
!var.value.address.autoDecrement) ||
(val.kind == DD_Address && var.kind == DD_Address &&
val.value.address.base == var.value.address.base &&
!val.value.address.hasIndex && !var.value.address.hasIndex &&
val.value.address.offset == 0 && var.value.address.offset == 0 &&
val.value.address.autoIncrement &&
var.value.address.autoDecrement));
}
Boolean isNextAddress(data, abCon)
DD data, abCon;
{
if (data.kind != DD_Address || abCon.kind != DD_Address) return(FALSE);
if (data.value.address.autoIncrement && abCon.value.address.autoIncrement ||
data.value.address.autoDecrement && abCon.value.address.autoDecrement)
return(TRUE);
return((data .value.address.base == Register &&
abCon.value.address.base == Register &&
abCon.value.address.offset == data .value.address.offset+1) ||
(data .value.address.base == abCon.value.address.base &&
abCon.value.address.offset == data .value.address.offset+4));
}
DD nextAddress(d)
DD d;
{
DD result;
result = d;
if (result.value.address.autoIncrement||result.value.address.autoDecrement)
return (result);
if (d.value.address.base == Register) {
assert(result.value.address.offset <= 15); /* TODO this should be last
allocatable register - 1 */
result.value.address.offset ++;
} else {
result.value.address.offset += 4;
result.value.address.baseIsTemporary = FALSE;
result.value.address.indexIsTemporary = FALSE;
}
return(result);
}
void vPushValue(p, c)
NodePtr p;
Context c;
{
Variable result;
result.data = nullDD;
result.abCon = nullDD;
switch (p->tag) {
case P_BUILTINLIT:
vPushValue(refToBuiltinFromToken(B_IT, p->b.builtinlit.whichType), c);
break;
case P_NILLIT:
result.data = nilDD;
result.abCon = nilDD;
vPush(result);
break;
case P_CHARLIT:
result.data.kind = DD_Manifest;
result.data.value.manifest = (int)p->b.charlit.string[0];
result.abCon = buildConCon(CHARACTERINDEX);
vPush(result);
break;
case P_BOOLLIT:
result.data.kind = DD_Manifest;
result.data.value.manifest = p->b.boollit.value;
result.abCon = buildConCon(BOOLEANINDEX);
vPush(result);
break;
case P_REALLIT:
result.data.kind = DD_RealManifest;
result.data.value.realmanifest = p->b.reallit.string;
result.abCon = buildConCon(REALINDEX);
vPush(result);
break;
case P_INTLIT:
result.data.kind = DD_Manifest;
result.data.value.manifest = atoi(p->b.intlit.string);
result.abCon = buildConCon(INTEGERINDEX);
vPush(result);
break;
case P_STRINGLIT:
result.data.kind = DD_Label;
result.data.value.label = nextLabelNumber++;
result.abCon = buildConCon(STRINGINDEX);
squirrelStringLiteral(result.data.value.label, p->b.stringlit.string);
vPush(result);
break;
case P_GLOBALREF:
resolveGlobal(p, (ValuePtr) NULL);
vPushValue(p->b.globalref.value, c);
break;
case P_ATLIT:
/*
* When we find an atlit as the value of some symbol, it is a reference
* to a particular object that was created at compile time.
*/
result.abCon = buildConCon(SIGNATUREINDEX);
result.data.kind = DD_OIDToCodePtr;
result.data.value.id = p->b.atlit.id;
ensureGenerate(p->b.atlit.id);
vPush(result);
break;
case P_OBLIT:
/*
* When we find an oblit as the value of some symbol, it is either a
* reference to a particular object that was created at compile time,
* or a reference to self.
*/
if (p == currentObject) {
result.abCon = buildAbConFromObject(p);
result.data.kind = DD_Self;
} else {
result.abCon = buildAbConFromObject(p);
assert(p->b.oblit.id != 0);
result.data.kind = DD_OIDToODP;
result.data.value.id = p->b.oblit.id;
}
vPush(result);
break;
default:
assert(FALSE);
}
}
void vPushOwnName(q)
NodePtr q;
{
NodePtr itsName;
assert(q->tag == P_OBLIT);
itsName = Construct(P_STRINGLIT, 0);
itsName->b.stringlit.string = ST_SymbolName(q->b.oblit.name->b.symdef.symbol);
vPushValue(itsName, anyContext);
FreeNode(itsName);
}
void vPushOwnType(q)
NodePtr q;
{
assert(q->tag == P_OBLIT);
assert(q->b.oblit.myat != NN);
vPushValue(q->b.oblit.myat, anyContext);
}
void vPushVariable(st)
Symbol st;
{
Variable v;
NodePtr ct;
/*
* Push the address of the thing.
*/
v.data.kind = DD_Address;
v.data.value.address = st->v.address;
if (st->value.CTinfo != NULL) {
v.abCon = buildAbCon(getID(st->value.ATinfo),getCodeID(st->value.CTinfo));
} else {
ct = resolveToCTOrAT(st->value.ATinfo);
if (ct->tag == P_OBLIT) {
v.abCon = buildAbCon(getID(st->value.ATinfo), getCodeOID(ct));
} else {
v.abCon = nextAddress(v.data);
setDDAbstractType(v.abCon, getID(st->value.ATinfo));
}
}
assert(vStackTop < &vStack[MAXVARIABLESTACKDEPTH]);
*++vStackTop = v;
}
Boolean hasARealValue(st)
register Symbol st;
{
register NodePtr ob;
if (st->isSelf) {
assert(st->value.value != NN);
return(TRUE);
} else if (st->value.value == NN) {
return (FALSE);
} else {
ob = st->value.value;
if (ob->tag == P_GLOBALREF) {
return(TRUE);
} else if (ob->tag == P_ATLIT || ob->tag == P_OBLIT) {
if (ob->b.oblit.f.writeSeparately) {
assert(ob->b.atlit.id != 0);
return(TRUE);
} else {
return(FALSE);
}
} else {
assert(FALSE);
/*NOTREACHED*/
}
}
}
DD vGetSymbolAbCon(st, data)
Symbol st;
DD data;
{
DD abcon;
NodePtr ct;
if (st->value.CTinfo != NULL) {
abcon = buildAbCon(getID(st->value.ATinfo), getCodeID(st->value.CTinfo));
} else {
ct = resolveToCTOrAT(st->value.ATinfo);
if (ct->tag == P_OBLIT) {
abcon = buildAbCon(getID(st->value.ATinfo), getCodeOID(ct));
} else {
abcon = nextAddress(data);
setDDAbstractType(abcon, getID(st->value.ATinfo));
}
}
return(abcon);
}
void vPushSymbol(st, c)
Symbol st;
Context c;
{
Variable v;
/*
* What this does is look at the value field of the reference and do the
* right thing. If the value is known then that value is used at compile
* time, which implies that the concrete type must be known as well. If it
* is not known, then if the concrete type is known we push a Variable with
* the Ab/Con set to a manifest and the value to the address of the
* symbol, otherwise both the value and the Ab/Con are addresses.
*/
if (hasARealValue(st)) {
vPushValue(st->value.value, c);
} else {
v.data.kind = DD_Address;
v.data.value.address = st->v.address;
v.abCon = vGetSymbolAbCon(st, v.data);
assert(vStackTop < &vStack[MAXVARIABLESTACKDEPTH]);
*++vStackTop = v;
}
}
void vSwap()
{
Variable v;
assert(vStackTop >= &vStack[1]);
v = *vStackTop;
*vStackTop = *(vStackTop - 1);
*(vStackTop - 1) = v;
}
Variable vPop()
{
assert(vStackTop >= &vStack[0]);
return(*vStackTop--);
}
void vDiscard()
{
assert(vStackTop >= &vStack[0]);
freeDD(vStackTop->data);
freeDD(vStackTop->abCon);
vStackTop --;
}
/*
* Discard the dd n from the top. To discard the top one use vDiscardN(0);
*/
void vDiscardN(n)
int n;
{
register int i;
assert(vStackTop >= &vStack[n]);
freeDD((vStackTop - n)->data);
freeDD((vStackTop - n)->abCon);
for (i = n; i > 0; i--) {
*(vStackTop - i) = *(vStackTop - i + 1);
}
vStackTop --;
}
/*
* Peek at the dd n from the top. To get the top one use vPeek(0);
*/
Variable *vPeek(n)
int n;
{
assert(vStackTop >= &vStack[n]);
return(vStackTop - (n));
}
Variable vTop()
{
assert(vStackTop >= &vStack[0]);
return(*vStackTop);
}
DD vPopData()
{
assert(vStackTop >= &vStack[0]);
return((*vStackTop--).data);
}
DD vPopAbCon()
{
assert(vStackTop >= &vStack[0]);
return((*vStackTop--).abCon);
}
DD vTopData()
{
assert(vStackTop >= &vStack[0]);
return((*vStackTop).data);
}
DD vTopAbCon()
{
assert(vStackTop >= &vStack[0]);
return((*vStackTop).abCon);
}
void ddGenerateAssign(vardata, varabcon, valdata, valabcon)
DD vardata, varabcon, valdata, valabcon;
{
Boolean doFunnyAbCon = FALSE;
IFTRACE(assign, 1) {
fprintf(stdout, "ddGenerateAssign:\n");
fprintf(stdout, "vardata == "); displayDD(stdout, vardata, '\n');
fprintf(stdout, "varabcon == "); displayDD(stdout, varabcon, '\n');
fprintf(stdout, "valdata == "); displayDD(stdout, valdata, '\n');
fprintf(stdout, "valabcon == "); displayDD(stdout, valabcon, '\n');
fprintf(stdout, "==> ");
}
if (isSameDD(valdata, vardata) && isSameDD(valabcon, varabcon)) {
IFTRACE(assign, 1) {
fprintf(stdout, "nothing\n");
}
return;
}
if (valabcon.kind == DD_AbCon && getDDAbstractType(varabcon) != (OID)0xff000000)
setDDAbstractType(valabcon, getDDAbstractType(varabcon));
if (vardata.kind == DD_Address && varabcon.kind == DD_Address) {
doFunnyAbCon = valabcon.kind == DD_Address &&
getDDAbstractType(valabcon) != getDDAbstractType(varabcon);
if (doFunnyAbCon) {
if (vardata.value.address.autoDecrement) {
assert(varabcon.value.address.autoDecrement);
doFunnyAbCon = FALSE;
}
}
assert(isNextAddress(vardata, varabcon));
if (valdata.kind == DD_Manifest && valabcon.kind == DD_Manifest) {
/*
* This is a case for a funny movq.
*/
#ifdef vax
if (valdata.value.manifest == 0 && valabcon.value.manifest == 0) {
emit("\tclrq\t");
writeDD(vardata, '\n');
IFTRACE(assign, 1) {
fprintf(stdout, "\tclrq\t");
displayDD(stdout, vardata, '\n');
}
} else {
emit("\tmovq\t$0x%08x%08x,",
valdata.value.manifest, valabcon.value.manifest);
writeDD(vardata, '\n');
IFTRACE(assign, 1) {
fprintf(stdout, "\tmovq\t$0x%08x%08x,",
valdata.value.manifest, valabcon.value.manifest);
displayDD(stdout, vardata, '\n');
}
}
#endif
#ifdef sun
emitMove(valdata, vardata, 'l');
emitMove(valabcon, varabcon, 'l');
IFTRACE(assign, 1) {
fprintf(stdout, "\tmovl\t$0x%08x,", valdata.value.manifest);
displayDD(stdout, vardata, '\n');
fprintf(stdout, "\tmovl\t$0x%08x,", valabcon.value.manifest);
displayDD(stdout, varabcon, '\n');
}
#endif
} else if (valdata.kind == DD_Address && valabcon.kind == DD_Address &&
isNextAddress(valdata, valabcon)) {
if (valabcon.value.address.autoIncrement) {
NodePtr ct;
DD newabcon;
ct = getBestInfoFromAbCon(valabcon);
if (getDDAbstractType(varabcon) == (OID) 0xff000000 ||
getDDAbstractType(valabcon) == (OID) 0xff000000) {
/* no sweat, we are cheating for some reason */
#ifdef vax
emitMove(valdata, vardata, 'q');
#endif
#ifdef sun
emitMove(valdata, vardata, 'l');
emitMove(valabcon, varabcon, 'l');
#endif
} else if (ct->tag == P_OBLIT) {
/* no sweat, we know the concrete type */
newabcon = buildAbConFromObject(ct);
if (getDDAbstractType(newabcon) != getDDAbstractType(varabcon)) {
/* we know the concrete type, but we expect a different one */
emitMove(valdata, vardata, 'l');
emit(POPABCON);
TRACE0(assign, 1, POPABCON);
newabcon = buildAbCon(getDDAbstractType(varabcon), getDDConcreteType(newabcon));
emitMove(newabcon, varabcon, 'l');
} else {
#ifdef vax
emitMove(valdata, vardata, 'q');
#endif
#ifdef sun
emitMove(valdata, vardata, 'l');
emitMove(valabcon, varabcon, 'l');
#endif
}
} else {
/* we always need to do them here */
emitMove(valdata, vardata, 'l');
fixDDView(valabcon, varabcon, getDDAbstractType(varabcon), FALSE);
}
} else if (doFunnyAbCon) {
emitMove(valdata, vardata, 'l');
fixDDView(valabcon, varabcon, getDDAbstractType(varabcon), TRUE);
} else {
#ifdef vax
emitMove(valdata, vardata, 'q');
#endif
#ifdef sun
if (vardata.value.address.autoDecrement) {
emitMove(valabcon, varabcon, 'l');
emitMove(valdata, vardata, 'l');
} else {
emitMove(valdata, vardata, 'l');
emitMove(valabcon, varabcon, 'l');
}
#endif
}
} else if (vardata.value.address.autoDecrement) {
/* push, so we have to do the abCon first */
assert(!doFunnyAbCon);
assert(varabcon.value.address.autoDecrement);
if (valdata.kind == DD_PSLCondition) {
/* we need to put the value from the PSL into somewhere */
Variable v;
v.data = valdata;
v.abCon = valabcon;
vForceToTemp(&v, TS_PSL);
valdata = v.data;
valabcon = v.abCon;
}
emitMove(valabcon, varabcon, 'l');
emitMove(valdata, vardata, 'l');
} else {
/* pop or dont care, so we do the data first */
assert(!doFunnyAbCon);
if (valdata.kind == DD_Address && valdata.value.address.autoIncrement)
assert(FALSE);
emitMove(valdata, vardata, 'l');
emitMove(valabcon, varabcon, 'l');
}
} else {
/* just the data */
assert(vardata.kind == DD_Address);
assert(varabcon.kind == DD_AbCon || varabcon.kind == DD_Manifest);
emitMove(valdata, vardata, 'l');
if (isPop(valabcon)) {
emit(POPABCON);
TRACE0(assign, 1, POPABCON);
}
}
freeDD(valdata);
freeDD(valabcon);
}
void ddGenerateMovqAssign(size, vardata, varabcon, valdata, valabcon)
int size;
DD vardata, varabcon, valdata, valabcon;
{
if (size == 8 && valabcon.kind == DD_AbCon) {
/* we need to worry since we need to do a movq */
Variable auxv, *aux = &auxv;
aux->data = pusher;
aux->abCon = pusher;
setDDAbstractType(aux->abCon, getDDAbstractType(valabcon));
ddGenerateAssign(aux->data, aux->abCon, valdata, valabcon);
aux->data = popper;
aux->abCon = popper;
ddGenerateAssign(vardata, varabcon, aux->data, aux->abCon);
} else {
ddGenerateAssign(vardata, varabcon, valdata, valabcon);
}
}
void vGenerateAssign()
{
register VariablePtr var, val;
assert(vStackTop >= &vStack[1]);
val = vStackTop;
var = (vStackTop - 1);
ddGenerateAssign(var->data, var->abCon, val->data, val->abCon);
(void) vPop();
(void) vPop();
}
void findTemp(v, size, brand)
Variable *v;
int size;
Brand brand;
{
int registerNo, stackAddress;
registerNo = allocateReg(size / 4, brand);
if (registerNo >= 0) {
v->data = buildRegisterDD(registerNo);
} else {
stackAddress = TS_Allocate(size, brand);
v->data.kind = DD_Address;
v->data.value.address = nullAddress;
v->data.value.address.base = regs_l;
v->data.value.address.baseIsTemporary = TRUE;
v->data.value.address.offset = stackAddress;
}
if (size == 8) v->abCon = nextAddress(v->data);
}
void vForceToTemp(v, which)
register Variable *v;
int which;
{
int registerNo, stackAddress;
DD newdata, newabcon;
NodePtr ct;
if (! (((which & TS_Stack) &&
v->data.kind == DD_Address &&
v->data.value.address.base == regs_sp &&
v->data.value.address.autoIncrement) ||
((which & TS_PSL) &&
v->data.kind == DD_PSLCondition) ||
((which & TS_Self) && v->data.kind == DD_Self) ||
((which & TS_Label) &&
v->data.kind == DD_Label))) return;
newabcon = v->abCon;
if (newabcon.kind != DD_AbCon) {
ct = resolveOIDToCTOrAT(getDDAbstractType(newabcon));
if (ct->tag == P_OBLIT) {
newabcon = buildAbCon(getDDAbstractType(newabcon), ct->b.oblit.codeOID);
}
}
if (newabcon.kind == DD_AbCon) {
registerNo = allocateReg(1, abConToBrand(newabcon));
if (registerNo >= 0) {
newdata = buildRegisterDD(registerNo);
} else {
stackAddress = TS_Allocate(4, abConToBrand(newabcon));
newdata.kind = DD_Address;
newdata.value.address = nullAddress;
newdata.value.address.base = regs_l;
newdata.value.address.baseIsTemporary = TRUE;
newdata.value.address.offset = stackAddress;
}
ddGenerateAssign(newdata, newabcon, v->data, v->abCon);
v->data = newdata;
v->abCon = newabcon;
} else {
/* check for thing on stack, if so, put it on stack */
if (v->abCon.value.address.autoIncrement) {
registerNo = -1;
} else {
registerNo = allocateReg(2, VariableBrand);
}
if (registerNo >= 0) {
newdata = buildRegisterDD(registerNo);
} else {
stackAddress = TS_Allocate(8, VariableBrand);
newdata.kind = DD_Address;
newdata.value.address = nullAddress;
newdata.value.address.base = regs_l;
newdata.value.address.baseIsTemporary = TRUE;
newdata.value.address.offset = stackAddress;
}
newabcon = nextAddress(newdata);
setDDAbstractType(newabcon, getDDAbstractType(v->abCon));
ddGenerateAssign(newdata, newabcon, v->data, v->abCon);
v->data = newdata;
v->abCon = newabcon;
}
}
typedef struct {
int regNo;
DD argument;
} KARec, *KARecPtr;
/*
* This one preempts all the kernel registers, assigns the given things to
* the given input registers, and claims the result register with the given
* brand.
*/
/*VARARGS2*/
DD preemptAndAssign(resultBrand, nArgs, firstArg)
Brand resultBrand;
int nArgs;
KARec firstArg;
{
KARecPtr args = &firstArg;
int i;
Boolean done[4];
DD d;
done[0] = done[1] = done[2] = done[3] = FALSE;
d.kind = DD_Address;
d.value.address = nullAddress;
d.value.address.base = Register;
for (i = 0; i < nArgs; i++) {
d.value.address.offset = args[i].regNo;
if (isSameDD(args[i].argument, d)) {
done[args[i].regNo] = TRUE;
}
}
for (i = 0; i < 4; i++) {
if (!done[i]) preemptReg(i, 1);
}
for (i = 0; i < nArgs; i++) {
if (!done[args[i].regNo]) {
claimReg(args[i].regNo, 1, DataBrand);
emitMove(args[i].argument, buildRegisterDD(args[i].regNo), 'l');
}
}
for (i = 0; i < nArgs; i++) {
freeReg(args[i].regNo, 1);
}
claimReg(regs_arg1, 1, resultBrand);
return(buildRegisterDD(regs_arg1));
}
void vDisplayStack()
{
register VariablePtr v;
for (v = vStackTop; v >= &vStack[0]; v--) {
fprintf(stdout, "Variable stack [%d]\n data -> ", v - &vStack[0]);
displayDD(stdout, v->data, '\n');
fprintf(stdout, " abCon-> ");
displayDD(stdout, v->abCon, '\n');
}
fflush(stdout);
}
typedef struct sStringLiteral {
int label;
char *string;
struct sStringLiteral *next;
} StringLiteral, *SLPtr;
static SLPtr slHead = NULL;
typedef struct sVectorLiteral {
int label;
int elementTypeSize;
OID vecCodeOID;
NodePtr vector;
struct sVectorLiteral *next;
} VectorLiteral, *VLPtr;
static VLPtr vlHead = NULL;
void squirrelStringLiteral(label, string)
int label;
char *string;
{
register SLPtr s;
s = (SLPtr) malloc(sizeof(StringLiteral));
s->next = slHead;
s->label = label;
s->string = string;
slHead = s;
}
void dumpStringLiterals()
{
register SLPtr s;
while (slHead != NULL) {
s = slHead;
slHead = s->next;
emitStringObject(s->string, s->label, (char *)NULL, 0);
free((char *) s);
}
}
void squirrelVectorLiteral(label, vector, elementTypeSize, vecCodeOID)
int label;
NodePtr vector;
int elementTypeSize;
OID vecCodeOID;
{
register VLPtr s;
s = (VLPtr) malloc(sizeof(VectorLiteral));
s->next = vlHead;
s->label = label;
s->elementTypeSize = elementTypeSize;
s->vecCodeOID = vecCodeOID;
s->vector = vector;
vlHead = s;
}
void dumpVectorLiterals()
{
register VLPtr s;
while (vlHead != NULL) {
s = vlHead;
vlHead = s->next;
emitVectorObject(s->vector, s->label, s->elementTypeSize, s->vecCodeOID);
free((char *) s);
}
}